﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Xml;
using SHomeWorkshop.LunarPresentation.Converts;
using SHomeWorkshop.LunarPresentation.Interfaces;

namespace SHomeWorkshop.LunarPresentation.Expressions
{
    public class Expander : MSExpression, ICollapsed
    {
        public Expander(SubPanel rootPanel, SubPanel parentPanel, Editor editor)
            : base(rootPanel, parentPanel, editor)
        {
            // 基类构造方法会调用“InitializeMSPanels”这个虚方法。

            this.chineseName = "扩展式";
        }

        private TextBlock expandButton;

        public TextBlock ExpandButton
        {
            get { return expandButton; }
        }

        private StackPanel topPanel;

        /// <summary>
        /// 放置按钮和主面板。
        /// </summary>
        public StackPanel TopPanel
        {
            get { return topPanel; }
        }

        private Border bottomBorder;

        /// <summary>
        /// 放置从面板。
        /// </summary>
        public Border BottomBorder
        {
            get { return bottomBorder; }
        }

        private StackPanel bottomPanel;

        private Rectangle handleRectangle;

        public Rectangle HandleRectangle
        {
            get { return handleRectangle; }
        }

        private static Thickness expanderBtnMargin = new Thickness(3, 0, 2, 0);

        private static Thickness expanderBtnPadding = new Thickness(2, 2, 1, 2);

        private static Thickness handleRectangleMargin = new Thickness(0, 0, 2, 0);

        private static string expanderBtnTooltip = "展开/折叠";

        protected override void InitializeMSPanels(SubPanel rootPanel, Editor editor)
        {
            this.basePanel.Orientation = Orientation.Vertical;

            this.topPanel = new StackPanel();
            this.topPanel.Orientation = Orientation.Horizontal;
            this.basePanel.Children.Add(this.topPanel);

            this.expandButton = new TextBlock()
            {
                Padding = Expander.expanderBtnPadding,
                Margin = Expander.expanderBtnMargin,
                TextAlignment = TextAlignment.Center,
                VerticalAlignment = VerticalAlignment.Center,
                ToolTip = Expander.expanderBtnTooltip,
            };

            this.expandButton.Focusable = false;

            Binding txtBinding = new Binding("CommentText");
            txtBinding.Source = this;
            txtBinding.Converter = new ExpanderBtnTextConverter();
            this.expandButton.SetBinding(TextBlock.TextProperty, txtBinding);

            MultiBinding foregroundBinding = new MultiBinding() { ConverterParameter = this };

            Binding editDefaultBackgroundBinding = new Binding("DefaultBackground");
            editDefaultBackgroundBinding.Source = this.editor;

            foregroundBinding.Bindings.Add(editDefaultBackgroundBinding);

            Binding exBackgroundBinding = new Binding("ExBackground");
            exBackgroundBinding.Source = this;

            foregroundBinding.Bindings.Add(exBackgroundBinding);

            foregroundBinding.Converter = new ExpanderBtnForegroundConverter();

            this.expandButton.SetBinding(TextBlock.ForegroundProperty, foregroundBinding);

            Binding backgroundBinding = new Binding("ExForeground");//反色
            backgroundBinding.Source = this;
            this.expandButton.SetBinding(TextBlock.BackgroundProperty, backgroundBinding);

            this.expandButton.MouseLeftButtonDown += new System.Windows.Input.MouseButtonEventHandler(expandButton_MouseLeftButtonDown);

            this.topPanel.Children.Add(this.expandButton);

            this.masterPanel = new SubPanel(rootPanel, null, editor, this);
            this.masterPanel.VerticalAlignment = VerticalAlignment.Center;
            this.topPanel.Children.Add(this.masterPanel);

            this.bottomBorder = new Border();
            this.bottomBorder.BorderThickness
                = this.bottomBorder.Margin
                = this.bottomBorder.Padding
                = new Thickness(1);

            if (editor != null)
            {
                this.bottomBorder.BorderBrush = Editor.DefaultForeground;
            }

            this.slavePanel = new SubPanel(rootPanel, null, editor, this);

            this.bottomPanel = new StackPanel();
            this.bottomPanel.Orientation = Orientation.Horizontal;

            //如果要支持拖动，就不能支持自动显示。
            handleRectangle = new Rectangle();
            handleRectangle.VerticalAlignment = System.Windows.VerticalAlignment.Stretch;
            handleRectangle.Fill = Brushes.Transparent;//this.Editor.BaseScrolledViewer.Background;
            handleRectangle.Margin = Expander.handleRectangleMargin;
            handleRectangle.MouseEnter += new System.Windows.Input.MouseEventHandler(handleRectangle_MouseEnter);
            handleRectangle.MouseLeave += new System.Windows.Input.MouseEventHandler(handleRectangle_MouseLeave);
            handleRectangle.MouseDown += new System.Windows.Input.MouseButtonEventHandler(handleRectangle_MouseDown);

            Binding handleRectangleWidthBinding = new Binding("ActualWidth");
            handleRectangleWidthBinding.Source = this.expandButton;
            BindingOperations.SetBinding(handleRectangle, WidthProperty, handleRectangleWidthBinding);

            bottomPanel.Children.Add(handleRectangle);
            bottomPanel.Children.Add(slavePanel);

            this.bottomBorder.Child = bottomPanel;
            this.bottomBorder.VerticalAlignment = VerticalAlignment.Center;
            this.basePanel.Children.Add(this.bottomBorder);

            RefreshSubPanelRelatios();
        }

        public static Brush expanderHandleBrush = Brushes.LightBlue;

        void handleRectangle_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
        {
            (sender as System.Windows.Shapes.Rectangle).Fill = Brushes.Transparent;
        }

        void handleRectangle_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e)
        {
            if (Editor != null)
            {
                (sender as System.Windows.Shapes.Rectangle).Fill = Editor.DefaultForeground;
            }
            else
            {
                (sender as System.Windows.Shapes.Rectangle).Fill = Expressions.Expander.expanderHandleBrush;
            }
        }

        void handleRectangle_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            Globals.selectedEditor.SelectedExpression = this;

            //如果本扩展式的左上角不在可视区，则尝试显示之。
            if (this.Editor == null) return;

            Point startPtOfEx = this.TranslatePoint(
                new Point(0, 0), Editor.BaseScrolledViewer);
            Editor editor = this.Editor;

            if (startPtOfEx.X < 0)
            {
                editor.BaseScrolledViewer.ScrollToHorizontalOffset(
                    startPtOfEx.X + editor.BaseScrolledViewer.HorizontalOffset - 20);
            }

            if (startPtOfEx.Y < 0)
            {
                editor.BaseScrolledViewer.ScrollToVerticalOffset(
                    startPtOfEx.Y + editor.BaseScrolledViewer.VerticalOffset - 20);
            }

            e.Handled = true;
        }

        //此功能改由编辑器的baseScrollViewer的右键弹起事件实现。
        //void expandButton_MouseRightButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        //{
        //    SetButtonText();
        //}

        /// <summary>
        /// 设置折叠按钮的文本。2011年6月14日改为与备注（注释）文本关联。
        /// </summary>
        public void SetButtonText()
        {
            #region 原有的单独设置按钮文本的代码。2011年6月14日
            //if (Editor != null) Editor.IsScrolling = false;//否则会变成拖动。

            //string text = Globals.ShowInputBox(Editor.ParentWindow, "请输入折叠按钮的自定义文本：", Title);
            //if (text != string.Empty)
            //{
            //    ModifingItem mi = new ModifingItem();
            //    Action action = new Action(this.ExID, -1, this.GetType().Name, "Title",
            //        this.Title, text);

            //    this.Title = text;

            //    mi.Add(action);
            //    this.Editor.Do(mi);
            //}
            #endregion

            Commands.Command.Comment(Globals.MainWindow);

            //e.Handled = true;
        }

        void expandButton_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            // 展开、折叠
            ModifingItem mi = new ModifingItem();
            Action action = new Action(this.ExID, -1, this.GetType().Name, "IsCollapsed",
                this.IsCollapsed.ToString(), (!this.IsCollapsed).ToString());

            this.IsCollapsed = !this.IsCollapsed;

            mi.Add(action); this.Editor.Do(mi);

            e.Handled = true;
        }

        //void expandButton_Click(object sender, RoutedEventArgs e)
        //{
        //    // 展开、折叠
        //    ModifingItem mi = new ModifingItem();
        //    Action action = new Action(this.ExID, -1, this.GetType().Name, "IsCollapsed",
        //        this.IsCollapsed.ToString(), (!this.IsCollapsed).ToString());

        //    this.IsCollapsed = !this.IsCollapsed;

        //    mi.Add(action); this.Editor.Do(mi);

        //    e.Handled = true;
        //}

        protected override void BuildChildren()
        {
            base.BuildChildren();

            if (this.XmlData == null) return;

            // 读取、建立括弧式相关内容。

            XmlNodeList panelNodes = this.XmlData.SelectNodes("Expression");
            foreach (XmlNode node in panelNodes)
            {
                if (node.GetAttributeString("Type") == TypeOfExpression.SubPanel.ToString()
                    && node.GetAttributeString("Location") == "Master")
                {
                    this.masterPanel.XmlData = node;
                }
                else if (node.GetAttributeString("Type") == TypeOfExpression.SubPanel.ToString()
                   && node.GetAttributeString("Location") == "Slave")
                {
                    this.slavePanel.XmlData = node;
                }
            }

            XmlAttribute attrCollpsed = this.XmlData.GetAttribute("Collpsed");
            if (attrCollpsed != null)
            {
                this.isCollapsed = Boolean.Parse(attrCollpsed.Value);

                if (this.isCollapsed)
                {
                    this.bottomBorder.Visibility = Visibility.Collapsed;
                }
                else
                {
                    this.bottomBorder.Visibility = Visibility.Visible;
                }

                RefreshSubPanelRelatios();
            }

            XmlAttribute attrInsideIndent = this.XmlData.GetAttribute("InsideIndent");
            if (attrInsideIndent != null)
            {
                this.isInsideIndent = Boolean.Parse(attrInsideIndent.Value);

                if (this.isInsideIndent == false)
                {
                    this.handleRectangle.Visibility = Visibility.Collapsed;
                }
            }

            #region 原有的单独设置折叠按钮文本的“读取”代码。2011年6月14日改为与备注（注释）文本关联。
            //XmlAttribute attrTitle = this.XmlData.GetAttribute("Title");
            //if (attrTitle != null)
            //{
            //    title = attrTitle.Value;
            //    //expandButton.Content = title;
            //    expandButton.Text = title;
            //}
            #endregion
        }

        #region 原有的单独设置折叠按钮文本的“读取”代码。2011年6月14日改为与备注（注释）文本关联。
        //private string title = "※";

        ///// <summary>
        ///// 折叠/展开按钮上的文本。
        ///// </summary>
        //public string Title
        //{
        //    get { return title; }
        //    set
        //    {
        //        if (title != value)
        //        {
        //            title = value;
        //            this.XmlData.SetAttribute("Title", title);
        //            //this.expandButton.Content = title;
        //            this.expandButton.Text = title;
        //            Editor.IsModified = true;
        //        }
        //    }
        //}
        #endregion

        public override void TurnOffMSPanel()
        {
            RunTurnOff();

            ModifingItem mi = new ModifingItem();
            Action action = new Action(this.ExID, this.ParentPanel.BasePanel.Children.IndexOf(this),
                this.GetType().Name, "TurnOffMSPanel", null, null);
            mi.Add(action);
            Editor.Do(mi);
        }

        protected override void RunTurnOff()
        {
            if (masterPanel == null || slavePanel == null) return;

            this.topPanel.Children.Remove(masterPanel);
            this.bottomPanel.Children.Remove(slavePanel);

            this.topPanel.Children.Add(slavePanel);
            this.bottomPanel.Children.Add(masterPanel);

            SubPanel temp = this.masterPanel;
            this.masterPanel = this.slavePanel;
            this.slavePanel = temp;

            this.masterPanel.XmlData.SetAttribute("Location", "Master");
            this.slavePanel.XmlData.SetAttribute("Location", "Slave");

            RefreshSubPanelRelatios();

            Editor.IsModified = true;
        }

        /// <summary>
        /// SubPanels属性用以在公式各层间导航，不是所有公式内部都嵌入子面板，
        /// 因此这个方法可能没有代码。
        /// 
        /// 在实际公式类，此一方法应设置：FirstSubPanel/LastSubPanel/SubPanels这三个属性的值。
        /// </summary>
        protected override void RefreshSubPanelRelatios()
        {
            this.subPanels.Clear();

            if (isCollapsed)
            {
                this.lastSubPanel = this.firstSubPanel = this.masterPanel;

                this.subPanels.Add(this.masterPanel);
                this.subPanels.Add(this.slavePanel);

                this.masterPanel.BottomSubPanel = null;
                this.slavePanel.TopSubPanel = null;// 取消两个子面板间的关联。

                this.bottomBorder.Visibility = Visibility.Collapsed;
            }
            else
            {
                this.firstSubPanel = this.masterPanel;
                this.lastSubPanel = this.slavePanel;

                this.SubPanels.Add(this.masterPanel);
                this.SubPanels.Add(this.slavePanel);

                //考虑到翻转，有必要加上两行：
                this.masterPanel.TopSubPanel = null;
                this.slavePanel.BottomSubPanel = null;

                this.masterPanel.BottomSubPanel = this.slavePanel;
                this.slavePanel.TopSubPanel = this.masterPanel;// 连接两个子面板。

                this.bottomBorder.Visibility = Visibility.Visible;
            }
        }

        #region Collpased Members

        private bool isCollapsed = false;//默认为折叠状态。

        public bool IsCollapsed
        {
            get
            {
                return isCollapsed;
            }
            set
            {
                if (value == isCollapsed) return;
                if (this.XmlData == null) return;

                isCollapsed = value;
                this.XmlData.SetAttribute("Collpsed", value.ToString());

                RefreshSubPanelRelatios();

                if (isCollapsed)
                {
                    if (Editor != null && Editor.SelectedExpression != this)
                    {
                        if (IsInSlavePanel(Editor.SelectedExpression) ||
                            Editor.SelectedExpression == this.slavePanel)
                        {
                            Editor.SelectedExpression = this;
                        }
                    }
                }

                Editor.IsModified = true;
            }
        }

        #endregion

        private bool isInsideIndent = true;//默认情况下是缩进的。

        public bool IsInsideIndent
        {
            get { return isInsideIndent; }
            set
            {
                if (value == isInsideIndent) return;
                if (this.XmlData == null) return;

                isInsideIndent = value;
                this.XmlData.SetAttribute("InsideIndent", value.ToString());

                if (isInsideIndent)
                {
                    handleRectangle.Visibility = Visibility.Visible;
                }
                else
                {
                    handleRectangle.Visibility = Visibility.Collapsed;
                }

                Editor.IsModified = true;
            }
        }

        private bool IsInSlavePanel(Expression ex)
        {
            if (ex == null) return false;
            Expression parentEx = (ex is SubPanel) ? (ex as SubPanel).ParentExpression : ex.ParentPanel;

            while (parentEx != null)
            {
                if (parentEx == this.slavePanel) return true;
                if (parentEx is SubPanel)
                {
                    parentEx = (parentEx as SubPanel).ParentExpression;
                }
                else
                {
                    parentEx = parentEx.ParentPanel;
                }
            }

            return false;
        }

        public override void UpdateExForegroundWithoutXmlChanging(Brush value)
        {
            base.UpdateExForegroundWithoutXmlChanging(value);

            this.exForeground = value;
            OnPropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs("ExForeground"));

            if (this.bottomBorder != null && value != null)
            {
                this.bottomBorder.BorderBrush = value;
            }
        }

        public override void SetProperty(string propertyName, string value)
        {
            base.SetProperty(propertyName, value);

            switch (propertyName)
            {
                //case "Indent":
                //    {
                //        this.Indent = int.Parse(value);
                //        break;
                //    }
                case "IsInsideIndent":
                    {
                        this.IsInsideIndent = bool.Parse(value);
                        break;
                    }
                #region 原有的单独设置折叠按钮文本的“读取”代码。2011年6月14日改为与备注（注释）文本关联。
                //case "Title"://折叠按钮的文本，经常可以用作标题。
                //    {
                //        this.Title = value;
                //        break;
                //    }
                #endregion
                case "IsCollapsed":
                    {
                        this.IsCollapsed = bool.Parse(value);
                        break;
                    }
            }
        }
    }
}
